#include "GameWidget.h"

#include <QtGui/QResizeEvent>

#include <string>
#include <cassert>

GameWidget::GameWidget(Ogre::Root* ogreRoot, QWidget* parent) :
	QGLWidget(parent),
	m_OgreRoot(ogreRoot),
	m_OgreRenderWindow(NULL)
{
	if ( ! parent )
	{
		throw std::runtime_error("Parent widget supplied was uninitialised!"); // interface requirement
	}

	// Create a NameValuePair list to store the parameters for the RenderWindow
	Ogre::NameValuePairList params;

	// Set parameters
	params["parentWindowHandle"] = Ogre::StringConverter::toString((unsigned long)(this->winId()));

	// Create RenderWindow
	m_OgreRenderWindow = m_OgreRoot->createRenderWindow( "QOgreWidget_RenderWindow",
														 this->width(),
														 this->height(),
														 false,
														 &params );

	m_OgreRenderWindow->setActive(true);
	m_OgreRenderWindow->setVisible(true);

	WId ogreWinId = 0x0;
	m_OgreRenderWindow->getCustomAttribute( "WINDOW", &ogreWinId );
	assert( ogreWinId ); // guaranteed to be valid due to the way it was created

	QWidget::create( ogreWinId );
	setAttribute( Qt::WA_OpaquePaintEvent ); // Don't update area behin RenderWindow

    // Set up StateManager and InputHandler
    unsigned long hWnd = (unsigned long)(this->winId());
    m_StateManager = new StateManager();
    m_InputHandler = new InputHandler(this, m_StateManager, hWnd);
    m_StateManager->requestStateChange(GAME_PAUSED);

    m_StepTimer = new QTimer();

    CreateSceneManager();

    // Setup scenes and all
    Setup();


}

void GameWidget::Setup(int p_Level)
{

    SetupResources(p_Level);

    m_PhysicsManager = PhysicsManager::CreateInstance(m_OgreSceneManager);

    m_Player = new Player("Player 1", m_OgreSceneManager, m_ResourceGroupName);

	CreateViewports();

    m_World = new World(m_OgreSceneManager);

    m_Obstacles = new Obstacles(m_OgreSceneManager);

    // set_up overlay
    m_Overlay = new Overlay();
    m_Overlay->ShowPause(true);

    // connect timer
    connect(m_StepTimer, SIGNAL(timeout()), this, SLOT(UpdateGame()));
    m_StepTimer->setInterval(1);
}

void GameWidget::UnloadLevel()
{

    // remove viewport
    m_OgreRenderWindow->removeAllViewports();

    // delete Scene
    delete m_World;
    m_World = 0;
    delete m_Player;
    m_Player = 0;
    delete m_Obstacles;
    m_Obstacles = 0;

    // delete Overlay
    delete m_Overlay;
    m_Overlay = 0;

    // remove Resource Group
    Ogre::ResourceGroupManager::getSingletonPtr()->destroyResourceGroup(m_ResourceGroupName);

}

void GameWidget::Reset()
{
	delete m_World;
    m_World = new World(m_OgreSceneManager);
	m_StateManager->requestStateChange(GAME);
}

void GameWidget::SetupResources(int p_Level)
{

    m_ResourceGroupName = "World" + std::to_string(p_Level);
    Ogre::ResourceGroupManager::getSingletonPtr()->addResourceLocation("resources/Worlds/" + std::to_string(p_Level), "FileSystem", m_ResourceGroupName);
    Ogre::ResourceGroupManager::getSingletonPtr()->initialiseResourceGroup(m_ResourceGroupName);

	// Create material manager
    //m_MaterialManager = Ogre::MaterialManager::getSingletonPtr();
}

void GameWidget::CreateSceneManager()
{
	// Get the SceneManager, in this case a generic one
	m_OgreSceneManager = m_OgreRoot->createSceneManager(Ogre::ST_GENERIC);
	m_OgreSceneManager->addRenderQueueListener(new Ogre::OverlaySystem());
}

void GameWidget::CreateViewports()
{
	Ogre::Camera* Camera = m_Player->GetCamera();

	// Create one viewport, entire window
	Ogre::Viewport* vp = m_OgreRenderWindow->addViewport(Camera);
	vp->setBackgroundColour(Ogre::ColourValue(0,0,0));

	// Alter the camera aspect ratio to match the viewport
    Camera->setAspectRatio(100/30);
            //vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));
//std::cout << "VIEWPORT" << vp->getActualWidth() << " " << vp->getActualHeight() << std::endl;
}


Ogre::RenderWindow* GameWidget::GetEmbeddedOgreWindow()
{
	assert(m_OgreRenderWindow); // guaranteed to be valid after construction
	return m_OgreRenderWindow;

}


void GameWidget::paintEvent(QPaintEvent* pEvent)
{
	this->update();
}


void GameWidget::resizeEvent(QResizeEvent* rEvent)
{
	if (rEvent)
	{
		QWidget::resizeEvent( rEvent);
	}

	if (m_OgreRenderWindow)
	{
		// since the underlying widget has already been updated we can source the resize values from there
		m_OgreRenderWindow->reposition( x(), y() );
		m_OgreRenderWindow->resize( width(), height() );
		m_OgreRenderWindow->windowMovedOrResized();

		// Tell InputHandler new extends for mouse capturing
		m_InputHandler->setWindowExtents(width(), height());
	}

}

void GameWidget::update()
{
	// Update Widget
	QWidget::update();

	// Render Frame
	m_OgreRoot->renderOneFrame();
	if (m_StateManager->getCurrentState() != SHUTDOWN)
	{
		if (m_StateManager->getCurrentState() == GAME)
		{
			// Capture input
			m_InputHandler->capture();

			// run the message pump
			Ogre::WindowEventUtilities::messagePump();

		}
        else if (m_StateManager->getCurrentState() == GAME_PAUSED || m_StateManager->getCurrentState() == LEVELCHANGE)
		{
			m_Overlay->ShowPause(true);
            m_StepTimer->stop();
            if (m_StateManager->getCurrentState() == LEVELCHANGE)
            {
                m_StateManager->requestStateChange(GAME_PAUSED);
                UnloadLevel();
                Setup(0);
            }
        }
		else if (m_StateManager->getCurrentState() == RESET)
		{
			Reset();
        }
	}
	else
	{
		this->parentWidget()->close();
	}
}


void GameWidget::UpdateGame()
{
	// Move Player
	m_Player->Update();
	m_Overlay->SetScore(m_Player->GetScore());

	m_PhysicsManager->Collide();
}

void GameWidget::mousePressEvent(QMouseEvent *event)
{
	if (event->button() == Qt::LeftButton && !m_InputHandler->isCapturing())
	{
		qDebug("Capturing Input");
		m_InputHandler->StartCapture();
		QCursor::setPos(this->width()/2, this->height()/2);

		m_StepTimer->start();
		m_Overlay->ShowPause(false);
		m_StepTimer->start();
	}
}

Player* GameWidget::GetPlayer()
{
    return m_Player;
}


Obstacles* GameWidget::GetObstacles()
{
    return m_Obstacles;
}
